const { chromium, firefox} = require('playwright');
const config = require("./config/scrapy.config.json");
const {createWorker} = require("tesseract.js")
const {PlaywrightCrawler, Dataset, ProxyConfiguration} = require("crawlee");
const EventEmitter = require("node:events");

const fs = require("fs");
const path = require('path');
const moment = require("moment");
const { TaskEndEvent } = require('./common');

var worker = null;

const startPlaywrightNew = async (tasks=[],zipDir,zipcode)=> {

    if(!worker){
        worker = await createWorker('eng',3,{logger:(m)=>{
            console.log(m)
        },errorHandler:(e)=>{
            console.error(e)
        }});
    }

    const processValidationCode = async (page)=>{
        if(await page.getByPlaceholder('Type characters').isVisible()){
            // await page.getByPlaceholder('Type characters').click();
            // const imgurl = await page.locator('form').getByRole('img').getAttribute('src');
            // console.log("got validate code img url: "+imgurl);
            // //TODO: ocr 不准，因为文字字形大小不一，还会黏连，-> use ai 识别?
            // const ret = await worker.recognize(imgurl);
            // const code = ret.data.text
            // console.log("got validate code: "+code)
            // await page.getByPlaceholder('Type characters').fill(code);
            // await page.getByRole('button', { name: 'Continue shopping' }).click();
            console.log("要手动处理验证码问题。。。 npx playwright 。。。。")
            throw new Error("要手动处理验证码问题。。。 npx playwright 。。。。")
        }    
    }

    const processWatchDog = async (page)=> {
        //看见看门狗图片
        const watchdogSelector = `img[alt="Sorry! Something went wrong on our end. Please go back and try again or go to Amazon's home page."]`;
        const dog = await page.locator(watchdogSelector);
        if(await dog.isVisible()){
            //看到看门狗，用命令重启浏览器，或者打开到亚马逊主页
            console.log("meet the watch dog..., or please run npx playwright")
            await page.goto("https://www.amazon.com")
            throw new Error("Meet the watch dog");
        }
    }

    const inputZipCode = async (page)=>{
            ///输邮编
            if(await page.locator("div.a-declarative.nav-global-location-slot-upsell-false").isVisible()){
                //需要登录
                await page.locator("div.a-declarative.nav-global-location-slot-upsell-false").click();
                //TODO: 如果看到要等录的页面的处理
            }else if(await page.locator('#nav-global-location-popover-link').isVisible()){
                //不需要登录
                await page.locator('#nav-global-location-popover-link').click();
                await page.getByLabel('or enter a US zip code').click();
                await page.getByLabel('or enter a US zip code').fill(zipcode);    
            }else{
                throw new Error("Can not see delivery to button");
            }
            if(await page.getByLabel('Apply').isVisible()){
                await page.getByLabel('Apply').click();
                await page.getByRole('button', { name: 'Continue' }).click();
            }else if(await page.getByRole('button', { name: 'Done' }).isVisible()){
                await page.getByRole('button', { name: 'Done' }).click();
            }else{
                throw new Error("No apply zip code button was found!")
            }
    }


    const writeData = (r={},keyword="")=> {
        const {html,dataitems} = r;
        console.log(`received result: ${JSON.stringify(r)}`)
        // console.clear()

        let dt = moment().format("HH_mm_ss");

        const commonPath = path.resolve(batchDir,dt+"_"+keyword).replace(/\s/,"_");

        const htmlPath = commonPath+".html";

        fs.writeFileSync(htmlPath,html);

        let its = (dataitems||[]).filter((i)=>i.dataAsin !== '');
        let asinCsvContent = its.map((item)=>{
            let title = (item.title||"").replace(/\n/g," ").replace(/,/g," ");
            let amount = item.amount||""
            if(item.dataAsin){
                return item.dataAsin+","+title+","+amount;
            }else{
                return "";
            }
        }).join("\n");

        const csvPath = commonPath+".csv";
        fs.writeFileSync(csvPath,asinCsvContent);

    }

    const processAisnData = async (page, keyword)=> {
        const deliveryto = await page.locator("span#glow-ingress-line2",{hasText:zipcode})
        const deliveryText = await deliveryto.innerText()
    
        if(deliveryText.includes(zipcode)){
            
            //输关键字
            await page.getByPlaceholder('Search Amazon').fill(keyword);
            //点按回车键
            await page.getByPlaceholder('Search Amazon').press('Enter');      
            
            await page.waitForLoadState("load");
    
            Cookie = await page.context().cookies(["https://amazon.com"]);
    
            const html = await page.content();
            
            console.log(`got html of url ${page.url()}`)
            const divLocator = await page.locator("div[data-asin]");
            const divs = await divLocator.all();
            var values = [];
            for(var i=0;i<divs.length;i++){
                let divEle = divs[i];
        
                let dataAsin = await divEle.getAttribute("data-asin");
        
                if(!dataAsin || dataAsin.length === 0){
                    continue;
                }
                let selector = "div[data-asin='" + dataAsin + "'] span";
                let span = await page.locator(selector);
                let title = ""
                try{
                    title = await span.first().innerText({timeout:config.waitTimeout});
                }catch(e){
                    console.error(e)
                    title = ""
                }

                const sellamountSelector = "div[data-asin='" + dataAsin + "'] span.a-size-base";

                var amount = ""
                if(await page.locator(sellamountSelector,{hasText:"bought in past month"}).isVisible()){
                    const amountSpan = await page.locator(sellamountSelector,{hasText:"bought in past month"});
                    amout = await amountSpan.innerText();
                }

                values.push({
                    dataAsin:dataAsin||"",
                    title:title||"",
                    amount
                });   
            }
    
            const dataitems = values||[]
            const result = {html,dataitems}

            await writeData(result,zipcode,keyword);

            (new EventEmitter()).emit(TaskEndEvent)

            console.log(`got result: ${JSON.stringify(result)}`.yellow)
            
        }else{
            console.log(`---------- Delivery Code is ${deliveryto} on : zipcode: ${zipcode}, keyword: ${keyword}`)
            throw new Error("DeliveryError")
        }
    }

    const urls = tasks.map((item)=>{
        return `https://www.amzon.com`
    }) 

    const proxyConfiguration = new ProxyConfiguration({
        proxyUrls:[
            "http://localhost:9000"
        ],
    });
    proxyConfiguration.isManInTheMiddle = true;
    //TODO: when use proxy failed

    const crawler = new PlaywrightCrawler({
        headless:!config.showBrowser,
        useSessionPool:true,
        navigationTimeoutSecs:60,
        maxRequestsPerCrawl: config.concurrentTaskNumber,
        maxRequestRetries:2,
        retryOnBlocked:false,
        persistCookiesPerSession:true,
        // proxyConfiguration:proxyConfiguration,
        failedRequestHandler({request, page, enqueueLinks, log},error={}){
            log.error(error)
        },
        async requestHandler({request, page,browserController ,proxyInfo, enqueueLinks, log}){
            try{
                await page.goto(request.url)
                //TODO: process
                // await processValidationCode(page);
           
                await processWatchDog(page);

                await inputZipCode(page);

                await processAisnData(page);
                
            }catch(e){
                log.error(e);
                throw e;
            }        
        }
     })

     await crawler.run(urls)
}

module.exports = {
    startPlaywrightNew
}